package rkw.election;

import java.util.List;
import java.util.UUID;

import javax.inject.Inject;

import org.eclipse.swt.widgets.Shell;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import rkw.communication.CommunicationService;
import rkw.database.DatabaseService;
import rkw.database.model.AdministratorToken;
import rkw.database.model.Election;
import rkw.database.model.ElectionVoter;
import rkw.database.model.Member;
import rkw.database.model.Token;
import rkw.database.model.Vote;
import rkw.exceptions.ElectionException;
import rkw.packager.PackagerService;
import core.database.ElectionStatus;
import core.exceptions.NoElectionFoundException;
import core.utils.ConfigPropertiesHolder;
import core.utils.Property;

@Service
public class ElectionServiceImpl implements ElectionService {
	private static final Logger L = LoggerFactory.getLogger(ElectionServiceImpl.class);

	private DatabaseService databaseService;
	private CommunicationService communicationService;
	private PackagerService packagerService;

	@Inject
	public ElectionServiceImpl(DatabaseService databaseService, CommunicationService communicationService, PackagerService packagerService) {
		L.debug("Tworze ElectionService");

		Assert.notNull(databaseService);
		Assert.notNull(communicationService);
		Assert.notNull(packagerService);

		this.databaseService = databaseService;
		this.communicationService = communicationService;
		this.packagerService = packagerService;
		this.packagerService.setCommunicationService(communicationService);
		this.packagerService.setDatabaseService(databaseService);

		L.debug("Utworzono ElectionService");
	}

	@Override
	public Election getElection(UUID token) throws NoElectionFoundException {
		AdministratorToken atoken = databaseService.getAdministratorTokenByValue(token.toString());
		if (atoken == null)
			throw new NoElectionFoundException();
		return atoken.getElection();
	}

	@Override
	public Member getMember(UUID token) {
		AdministratorToken atoken = databaseService.getAdministratorTokenByValue(token.toString());
		if (atoken == null)
			return null;
		return atoken.getMember();
	}

	@Override
	public void verifyNonresidentVoter(Election election, String voterIdentificationField, Shell responseShell) {
		communicationService.sendVerifyNonResidentVoter(election.getIdentificationField(), voterIdentificationField, responseShell);
	}

	@Override
	public Boolean verifyVoter(Election election, String voterIdentificationField) {
		Boolean result = databaseService.verifyVoter(election.getIdentificationField(), voterIdentificationField);

		if (result)
			packagerService.notifyAboutVoterVerification(voterIdentificationField);

		return result;
	}

	@Override
	public void startElection(UUID token) throws ElectionException {
		if (databaseService.getStartedElection() != null)
			throw new ElectionException("Other Election is already started.");
		Election e = getElection(token);
		if (e.getStatus() == ElectionStatus.COMPLETED)
			throw new ElectionException("This Election has already been ended.");
		e.setStatus(ElectionStatus.INPROGRESS);
		e = databaseService.storeElection(e);
		communicationService.sendElectionStatusMessage(e.getIdentificationField(), e.getStatus());
	}

	@Override
	public void endElection(UUID token) {
		Election e = databaseService.getStartedElection();
		if (e != null) {
			packagerService.sendVotesPackage();
			packagerService.sendVotersPackage();
			e.setStatus(ElectionStatus.COMPLETED);
			e = databaseService.storeElection(e);
			communicationService.sendElectionStatusMessage(e.getIdentificationField(), e.getStatus());
		}
	}

	@Override
	public Election getCurrentElection() {
		return databaseService.getStartedElection();
	}

	@Override
	public Boolean verifyRegistrationToken(UUID token) {
		Election e = getElection(token);
		Election currentElection = getCurrentElection();
		return currentElection != null ? e.getIdentificationField().longValue() == getCurrentElection().getIdentificationField().longValue() : false;
	}

	@Override
	public void handleVote(UUID voterToken, String vote) {
		boolean result = databaseService.handleVote(voterToken, new Vote(vote, getCurrentElection()));
		if(result == true) {
			packagerService.notifyAboutNewVote();
		}
	}

	@Override
	public UUID generateToken() {
		UUID t = UUID.randomUUID();
		Token token = new Token(t.toString());
		databaseService.saveToken(token);
		return t;
	}

	@Override
	public Boolean verifyTokenWithCurrentElection(UUID token) {
		Election tokenElection = getElection(token);
		Election currentElection = getCurrentElection();
		if (tokenElection != null && currentElection != null)
			return tokenElection.getIdentificationField() == currentElection.getIdentificationField() ? true : false;
		return false;
	}

	@Override
	public List<ElectionVoter> findElectionVotersLike(Election election, String text) {
		return databaseService.findVotersLike(election, text);
	}

	@Override
	public AdministratorToken getAdministratorTokenByValue(UUID token) {
		return databaseService.getAdministratorTokenByValue(token.toString());
	}

}